home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 2
/
Atari Mega Archive CD - Volume 2.iso
/
minix
/
up1510b.tgz
/
up1510b
/
src
/
tools
/
build.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-07-15
|
17KB
|
571 lines
/* This program takes the previously compiled and linked pieces of the
* operating system, and puts them together to build a boot diskette.
* The files are read and put on the boot diskette in this order:
*
* bootblok: the diskette boot program
* kernel: the operating system kernel
* mm: the memory manager
* fs: the file system
* init: the system initializer
* menu: the selection menu
*
* The bootblok file goes in sector 0 of the boot diskette. The operating system
* begins directly after it. The kernel, mm, fs, init, and menu are each
* padded out to a multiple of CLICK_SIZE bytes, and then concatenated into a
* single file beginning 512 bytes into the file. The first byte of sector 1
* contains executable code for the kernel. There is no header present.
*
* After the boot image has been built, build goes back and makes several
* patches to the image file or diskette:
*
* 1. The last 4 words of the boot block are set as follows:
* Word at 504: Number of sectors to load
* Word at 506: start of data of menu in clicks
* Word at 508: 0
* Word at 510: start of text of menu in clicks
*
* 2. Build writes a table into the first 8 words of the kernel's
* data space. It has 4 entries, the text and data size in clicks for each
* program. The kernel needs this information to run mm, fs, and
* init.
*
* 3. The origin and size of the init program are patched into bytes 4-9
* of the file system data space. The file system needs this
* information, and expects to find it here.
*
* Build is called by:
*
* build bootblok kernel mm fs init menu image
*
* to get the resulting image onto the file "image".
*/
#include "outmix.h"
#ifdef TOS
#include "fakeunix.c"
#else
long lseek();
#endif
#define PROGRAMS 5 /* kernel + mm + fs + init + menu = 5 */
#define PROG_ORG 0 /* where does kernel begin in abs mem */
#define SECTOR_SIZE 512 /* size of buf */
#define READ_UNIT 512 /* how big a chunk to read in */
#define KERNEL_D_MAGIC 0x526F /* identifies kernel data space */
#define FS_D_MAGIC 0xDADA /* identifies fs data space */
#define CLICK_SIZE 256
#define CLICK_SHIFT 8
#define KERN 0
#define MM 1
#define FS 2
#define INIT 3
#define FSCK 4
int image; /* file descriptor used for output file */
int cur_sector; /* which 512-byte sector to be written next */
int buf_bytes; /* # bytes in buf at present */
char buf[SECTOR_SIZE]; /* buffer for output file */
char zero[SECTOR_SIZE]; /* zeros, for writing bss segment */
long cum_size; /* Size of kernel+mm+fs+init */
long all_size; /* Size of all 5 programs */
struct sizes {
long text_size; /* size in bytes */
long data_size; /* size in bytes */
long bss_size; /* size in bytes */
short secs; /* #sectors written */
short nulls; /* #sectors not written */
} sizes[PROGRAMS];
char *name[] = {"\nkernel", "mm ", "fs ", "init ", "menu "};
main(argc, argv)
int argc;
char *argv[];
{
/* Copy the boot block and the 5 programs to the output. */
int i;
if (argc != PROGRAMS+3) pexit("seven file names expected. ", "");
create_image(argv[7]); /* create the output file */
/* Go get the boot block and copy it to the output file or diskette. */
copy1(argv[1]);
/* Copy the 5 programs to the output file or diskette. */
for (i = 0; i < PROGRAMS; i++) copy2(i, argv[i+2]);
flush();
printf(" ----- -----\n");
#ifdef PCIX
printf("Operating system size %29ld %5lx\n", cum_size, cum_size);
printf("\nTotal size including menu is %ld.\n", all_size);
#else
printf("Operating system size %29D %5X\n", cum_size, cum_size);
printf("\nTotal size including menu is %D.\n", all_size);
#endif
/* Make the three patches to the output file or diskette. */
patch1(all_size);
patch2();
patch3();
exit(0);
}
copy1(file_name)
char *file_name;
{
/* Copy the specified file to the output. The file has no header. All the
* bytes are copied, until end-of-file is hit.
*/
int fd, bytes_read;
char inbuf[READ_UNIT];
if ( (fd = open(file_name, 0)) < 0) pexit("can't open ",file_name);
do {
bytes_read = read(fd, inbuf, READ_UNIT);
if (bytes_read < 0) pexit("read error on file ", file_name);
if (bytes_read > 0) wr_out(inbuf, bytes_read);
} while (bytes_read > 0);
flush();
close(fd);
}
copy2(num, file_name)
int num; /* which program is this (0 - 4) */
char *file_name; /* file to open */
{
/* Open and read a file, copying it to output. First read the header,
* to get the text, data, and bss sizes.
* Read in all of text and initialized data. Perform relocation.
* Write the text, data, and bss to output. The sum of these three pieces
* must be padded upwards to a multiple of CLICK_SIZE, if need be. The individual
* pieces need not be multiples of CLICK_SIZE bytes.
*/
int fd, count, rest, filler;
unsigned length, n1;
long reloffset, reloshift, tot_bytes;
char *buf1, buf2[1024];
register char *p1, *p2;
register c, n2;
struct exec exec;
long b4;
extern char *malloc();
if ( (fd = open(file_name, 0)) < 0) pexit("can't open ", file_name);
/* Read the header to see how big the segments are. */
read_header(fd, &exec, file_name);
reloshift = cum_size;
reloffset = SZ_HEAD + exec.a_tsize + exec.a_dsize + exec.a_ssize;
/* Pad the total size to a CLICK_SIZE-byte multiple, if needed. */
tot_bytes = exec.a_tsize + exec.a_dsize + exec.a_bsize;
rest = (int)(tot_bytes % CLICK_SIZE);
filler = (rest > 0 ? CLICK_SIZE - rest : 0);
exec.a_bsize += filler;
tot_bytes += filler;
if (num < FSCK) cum_size += tot_bytes;
all_size += tot_bytes;
/* Record the size information in the table. */
sizes[num].text_size = exec.a_tsize;
sizes[num].data_size = exec.a_dsize;
sizes[num].bss_size = exec.a_bsize;
sizes[num].secs = cur_sector;
/* Print a message giving the program name and size, except for menu. */
if (num < FSCK) {
printf("%s text=%5D data=%5D bss=%5D tot=%5D hex=%4X\n",
name[num],
exec.a_tsize, exec.a_dsize, exec.a_bsize,
tot_bytes, tot_bytes);
}
/* Read in relocation info from the exec file and relocate.
* Relocation info is in GEMDOS format. Only longs can be relocated.
*
* The GEMDOS format starts with a long L: the offset to the
* beginning of text for the first long to be relocated.
* If L==0 then no relocations have to be made.
*
* The long is followed by zero or more bytes. Each byte B is
* processed separately, in one of the following ways:
*
* B==0:
* end of relocation
* B==1:
* no relocation, but add 254 to the current offset
* B==0bWWWWWWW0:
* B is added to the current offset and the long addressed
* is relocated. Note that 00000010 means 1 word distance.
* B==0bXXXXXXX1:
* illegal
*/
/* Allocate memory and read in the text+data and relocation */
length = exec.a_tsize + exec.a_dsize;
if (length != exec.a_tsize + exec.a_dsize)
pexit("more than 64k ", file_name);
buf1 = malloc(length);
if (buf1 == 0)
pexit("too big ", file_name);
p1 = buf1;
n1 = length;
while (n1 != 0) {
count = (n1 < 16*1024 ? n1 : 16*1024);
if (read(fd, p1, count) != count)
pexit("read error on file ", file_name);
n1 -= count;
p1 += count;
}
if (lseek(fd, reloffset, 0) < 0)
pexit("can't seek ", file_name);
p1 = buf1;
p2 = buf2;
n2 = read(fd, p2, (int)sizeof(buf2));
if (n2 < (int)sizeof(long))
pexit("relocation info missing on file ", file_name);
if (*((long *)p2) != 0) {
p1 += *((long *)p2);
n2 -= (int)sizeof(long);
p2 += (int)sizeof(long);
for (;;) { /* once per relocation */
if (p1 < buf1 || p1 >= &buf1[length])
pexit("bad relocation in ", file_name);
getstruc((char *)&b4, "M4", p1);
/* printf("%X L: %X